// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "MatchProfilesEntry.h"
#include "JsonUtils.h"

#include "MatchProfilesEntry.g.cpp"

using namespace Microsoft::Terminal::Settings::Model;

static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view CommandlineKey{ "commandline" };
static constexpr std::string_view SourceKey{ "source" };

namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
    MatchProfilesEntry::MatchProfilesEntry() noexcept :
        MatchProfilesEntryT<MatchProfilesEntry, ProfileCollectionEntry>(NewTabMenuEntryType::MatchProfiles)
    {
    }

    Json::Value MatchProfilesEntry::ToJson() const
    {
        auto json = NewTabMenuEntry::ToJson();

        JsonUtils::SetValueForKey(json, NameKey, _Name);
        JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline);
        JsonUtils::SetValueForKey(json, SourceKey, _Source);

        return json;
    }

    winrt::com_ptr<NewTabMenuEntry> MatchProfilesEntry::FromJson(const Json::Value& json)
    {
        auto entry = winrt::make_self<MatchProfilesEntry>();

        JsonUtils::GetValueForKey(json, NameKey, entry->_Name);
        JsonUtils::GetValueForKey(json, CommandlineKey, entry->_Commandline);
        JsonUtils::GetValueForKey(json, SourceKey, entry->_Source);

        return entry;
    }

    bool MatchProfilesEntry::MatchesProfile(const Model::Profile& profile)
    {
        // We use an optional here instead of a simple bool directly, since there is no
        // sensible default value for the desired semantics: the first property we want
        // to match on should always be applied (so one would set "true" as a default),
        // but if none of the properties are set, the default return value should be false
        // since this entry type is expected to behave like a positive match/whitelist.
        //
        // The easiest way to deal with this neatly is to use an optional, then for any
        // property to match we consider a null value to be "true", and for the return
        // value of the function we consider the null value to be "false".
        auto isMatching = std::optional<bool>{};

        if (!_Name.empty())
        {
            isMatching = { isMatching.value_or(true) && _Name == profile.Name() };
        }

        if (!_Source.empty())
        {
            isMatching = { isMatching.value_or(true) && _Source == profile.Source() };
        }

        if (!_Commandline.empty())
        {
            isMatching = { isMatching.value_or(true) && _Commandline == profile.Commandline() };
        }

        return isMatching.value_or(false);
    }

    Model::NewTabMenuEntry MatchProfilesEntry::Copy() const
    {
        auto entry = winrt::make_self<MatchProfilesEntry>();
        entry->_Name = _Name;
        entry->_Commandline = _Commandline;
        entry->_Source = _Source;
        return *entry;
    }
}
